package com.atguigu.gmall.order.service.impl;

import com.alibaba.fastjson.JSON;
import com.atguigu.gmall.common.constant.MqConst;
import com.atguigu.gmall.common.service.RabbitService;
import com.atguigu.gmall.common.util.HttpClientUtil;
import com.atguigu.gmall.model.enums.OrderStatus;
import com.atguigu.gmall.model.enums.ProcessStatus;
import com.atguigu.gmall.model.order.OrderDetail;
import com.atguigu.gmall.model.order.OrderInfo;
import com.atguigu.gmall.order.mapper.OrderDetailMapper;
import com.atguigu.gmall.order.mapper.OrderInfoMapper;
import com.atguigu.gmall.order.service.OrderService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

@Service
public class OrderServiceImpl extends ServiceImpl<OrderInfoMapper,OrderInfo> implements OrderService {

    @Autowired
    private OrderInfoMapper orderInfoMapper;
    @Autowired
    private OrderDetailMapper orderDetailMapper;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private RabbitService rabbitService;

    @Value("${ware.url}")
    private String wareUrl;

    //提交订单
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long saveOrderInfo(OrderInfo orderInfo) {
        //total_amount  //商品总数量
        orderInfo.sumTotalAmount();
        //order_status  //订单状态
        orderInfo.setOrderStatus(OrderStatus.UNPAID.name());
        //订单交易编号
        String outTradeNo = "ATGUIGU"+System.currentTimeMillis()+new Random().nextInt(10000);
        orderInfo.setOutTradeNo(outTradeNo);
        //订单的描述信息
        orderInfo.setTradeBody("购买国产手机 嘎嘎香");
        //order_time  订单操作时间
        orderInfo.setOperateTime(new Date());
        //expire_time 过期时间:所有的商品默认为24小时
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.DATE,1);
        orderInfo.setExpireTime(calendar.getTime());
        //订单进度状态
        orderInfo.setProcessStatus(ProcessStatus.UNPAID.name());
        orderInfoMapper.insert(orderInfo);
        //获取订单Id
        Long orderId = orderInfo.getId();
        //获取订单明细集合
        List<OrderDetail> orderDetailList = orderInfo.getOrderDetailList();
        if (!CollectionUtils.isEmpty(orderDetailList)){
            orderDetailList.forEach(orderDetail -> {
                //插入订单编号
                orderDetail.setOrderId(orderId);
                //写入数据库
                orderDetailMapper.insert(orderDetail);
            });
        }
        this.rabbitService.sendDelayMsg(MqConst.EXCHANGE_DIRECT_ORDER_CANCEL,MqConst.ROUTING_ORDER_CANCEL,orderId,MqConst.DELAY_TIME);
        return orderInfo.getId();
    }

    //返回流水号
    @Override
    public String getTradeNo(String userId) {
        String key = "tradeNo"+userId;
        //声明一个流水号
        String tradeNo = UUID.randomUUID().toString();
        //存入redis
        redisTemplate.opsForValue().set(key,tradeNo);
        return tradeNo;
    }

    //比较流水号
    @Override
    public Boolean checkTradeNo(String tradeNo,String userId) {
        String key = "tradeNo"+userId;
        //获取缓存流水号
        String redisTradeNo = (String) this.redisTemplate.opsForValue().get(key);
        //返回比较结果
        return tradeNo.equals(redisTradeNo);
    }

    @Override
    public void delTradeNo(String userId) {
        String key = "tradeNo"+userId;
        this.redisTemplate.delete(key);
    }

    //校验库存
    @Override
    public Boolean checkStock(Long skuId, Integer skuNum) {
        //远程调用库存系统接口
        String res = HttpClientUtil.doGet(wareUrl + "/hasStock?skuId=" + skuId + "&num=" + skuNum);
        return "1".equals(res);
    }

    //查看我的订单
//    @Override
//    public IPage<OrderInfo> getMyOrderList(Page<OrderInfo> orderInfoPage, String userId) {
//        //查询两张表 orderInfo orderDetail
//        IPage<OrderInfo> infoIPage = orderInfoMapper.selectMyOrder(orderInfoPage,userId);
//        infoIPage.getRecords().forEach(orderInfo -> {
//            String statusName = OrderStatus.getStatusNameByStatus(orderInfo.getOrderStatus());
//            orderInfo.setOrderStatusName(statusName);
//        });
//        return infoIPage;
//    }

    @Override
    public IPage<OrderInfo> getMyOrderList(Page<OrderInfo> orderInfoPage, String userId,String orderStatus) {
        //查询两张表 orderInfo orderDetail
        IPage<OrderInfo> infoIPage = orderInfoMapper.selectMyOrder(orderInfoPage,userId,orderStatus);
        infoIPage.getRecords().forEach(orderInfo -> {
            String statusName = OrderStatus.getStatusNameByStatus(orderInfo.getOrderStatus());
            orderInfo.setOrderStatusName(statusName);
        });
        return infoIPage;
    }

    //取消订单
    @Override
    public void execExpiredOrder(Long orderId) {
        //  根据订单Id , 更新订单状态 {PAID ,SPLIT}
        this.updateOrderStatus(orderId,ProcessStatus.CLOSED);

        this.rabbitService.sendMsg(MqConst.EXCHANGE_DIRECT_PAYMENT_CLOSE,MqConst.ROUTING_PAYMENT_CLOSE,orderId);
    }

    //查询订单与订单明细
    @Override
    public OrderInfo getOrderInfo(Long orderId) {
        OrderInfo orderInfo = orderInfoMapper.selectById(orderId);
        if (orderInfo!=null){
            List<OrderDetail> orderDetailList = this.orderDetailMapper.selectList(new QueryWrapper<OrderDetail>().eq("order_id", orderId));
            orderInfo.setOrderDetailList(orderDetailList);
        }
        return orderInfo;
    }

    public void updateOrderStatus(Long orderId, ProcessStatus processStatus) {
        OrderInfo orderInfo = new OrderInfo();
        orderInfo.setId(orderId);
        //更新订单状态
        orderInfo.setOrderStatus(processStatus.getOrderStatus().name());
        //更新订单进度状态
        orderInfo.setProcessStatus(processStatus.name());
        orderInfo.setUpdateTime(new Date());
        this.orderInfoMapper.updateById(orderInfo);
    }

    //发送消息给库存系统
    @Override
    public void sendOrderMsg(Long orderId) {
        this.updateOrderStatus(orderId,ProcessStatus.NOTIFIED_WARE);
        //构成json字符串  orderInfo --> JSON
        //orderInfo --> map -- JSON
        OrderInfo orderInfo = this.getOrderInfo(orderId);
        //将orderInfo转换为map
        Map map = this.wareJson(orderInfo);
        //发送消息
        this.rabbitService.sendMsg(MqConst.EXCHANGE_DIRECT_WARE_STOCK,MqConst.ROUTING_WARE_STOCK, JSON.toJSONString(map));


    }

    //将orderInfo转换为map
    public Map wareJson(OrderInfo orderInfo) {
        HashMap<String, Object> map = new HashMap<>();
        //给map赋值
        map.put("orderId",orderInfo.getId());
        map.put("consignee", orderInfo.getConsignee());
        map.put("consigneeTel", orderInfo.getConsigneeTel());
        map.put("orderComment", orderInfo.getOrderComment());
        map.put("orderBody", orderInfo.getTradeBody());
        map.put("deliveryAddress", orderInfo.getDeliveryAddress());
        //paymentWay ‘1’ 为货到付款，‘2’为在线支付。
        map.put("paymentWay", "2");
        map.put("wareId", orderInfo.getWareId());// 仓库Id ，减库存拆单时需要使用！
        //赋值订单明细
        List<OrderDetail> orderDetailList = orderInfo.getOrderDetailList();
        List<HashMap<String, Object>> detailList = orderDetailList.stream().map(orderDetail -> {
            HashMap<String, Object> hashMap = new HashMap<>();
            hashMap.put("skuId", orderDetail.getSkuId());
            hashMap.put("skuNum", orderDetail.getSkuNum());
            hashMap.put("skuName", orderDetail.getSkuName());
            return hashMap;
        }).collect(Collectors.toList());
        map.put("details",detailList);
        return map;
    }

    //拆单
    @Override
    public List<OrderInfo> orderSplit(String orderId, String wareSkuMap) {
        /**
         * 1.先获取到原始订单
         * 2.将wareSkuMap变为可操作对象
         * 3.获取子订单 并给子订单赋值
         * 4.重新保存子订单
         * 5.将子订单添加到集合中
         * 6.更改原始订单状态
         */
        List<OrderInfo> orderInfoList = new ArrayList<>();
        OrderInfo orderInfoOrigin = this.getOrderInfo(Long.parseLong(orderId));
        List<Map> mapList = JSON.parseArray(wareSkuMap, Map.class);
        //判断
        if (!CollectionUtils.isEmpty(mapList)){
            for (Map map : mapList) {
                String wareId = (String) map.get("wareId");
                List<String> skuIdList = (List<String>) map.get("skuIds");
                //
                OrderInfo subOrderInfo = new OrderInfo();
                //属性拷贝
                BeanUtils.copyProperties(orderInfoOrigin,subOrderInfo);
                //防止主键冲突
                subOrderInfo.setId(null);
                //赋值父id
                subOrderInfo.setParentOrderId(Long.parseLong(orderId));
                //赋值仓库Id
                subOrderInfo.setWareId(wareId);
                //赋值子订单明细
                List<OrderDetail> orderDetailList = orderInfoOrigin.getOrderDetailList().stream().filter(orderDetail -> {
                    return skuIdList.contains(orderDetail.getSkuId().toString());
                }).collect(Collectors.toList());
                //赋值子订单明细
                subOrderInfo.setOrderDetailList(orderDetailList);
                //计算总金额
                subOrderInfo.sumTotalAmount();
                //保存子订单
                this.saveOrderInfo(subOrderInfo);
                orderInfoList.add(subOrderInfo);
            }
        }
        this.updateOrderStatus(Long.parseLong(orderId),ProcessStatus.SPLIT);
        return orderInfoList;
    }

    @Override
    public void execExpiredOrder(Long orderId, String flag) {
        //根据订单id更新订单状态
        this.updateOrderStatus(orderId,ProcessStatus.CLOSED);
        //判断是否需要关闭paymentInfo
        if ("1".equals(flag)){
            return;
        }
        //退款时 关闭paymentInfo orderInfo
        this.rabbitService.sendMsg(MqConst.EXCHANGE_DIRECT_PAYMENT_CLOSE,MqConst.ROUTING_PAYMENT_CLOSE,orderId);

    }
}
